#include "test_vulkan.h"

test::test() 
	: test({1280, 1080, "Vulkan"})
{
}

test::test(windowInfo w_info) 
	:w_info{w_info}, window(nullptr)
{
	initWindow();
	initVulkan();
}

void test::initWindow() {
	// glfwInit是GLFW库的函数，用于初始化GLFW库的内部状态
	if (glfwInit() == GLFW_FALSE) {
		std::cout << "Failed to init glfw!" << std::endl;
		throw std::runtime_error("Failed to init glfw!");
	}
	// glfwWindowHint用于设置GLFW窗口属性的函数
	glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
	glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
	// glfwCreateWindow是GLFW库的函数，用于创建新的窗口，并为该窗口创建Vulkan上下文
	// GLFWwindow是GLFW库的结构体，用于表示窗口和其相关资源的结构体
	this->window = glfwCreateWindow(this->w_info.width, this->w_info.height, this->w_info.title.c_str(), nullptr, nullptr);
	if (this->window == nullptr) {
		std::cout << "Failed to create window!" << std::endl;
		throw std::runtime_error("Failed to create window!");
	}
}

void test::initVulkan() {
	createInstance();
	setupMessenger();
	createSurface();
	pickupPhysicalDevice();
	createLogicDevice();
	createSwapChain();
	createImageView();
	GetSwapChainImage(this->swapChainImages);
	createRenderPass();
	// 渲染通道 主要用于组织和管理渲染过程中的资源和同步，定义了资源的使用顺序、操作顺序和同步需求
	// 渲染管线 主要用于具体的渲染处理，通过着色器和图形硬件的各个固定功能阶段来执行渲染操作
	createGraphicsPipeline();
	createFrameBuffers();
}

void test::createInstance() {
	if (enabledValidationLayer && !checkValidationLayerSupport()) {
		throw std::runtime_error("Validation layer is not available!");
	}
	// VkApplicationInfo用于描述与应用程序相关的信息
	// sType 结构体标识
	// pApplicationName 应用程序的名称，作为一个字符串传入
	// applicationVersion 应用程序的版本号
	// apiVersion 要求的Vulkan API版本号
	// pEngineName 应用程序使用的引擎名称
	// engineVersion 引擎的版本号
	VkApplicationInfo appInfo{};
	appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
	appInfo.pApplicationName = "Vulkan";
	appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
	appInfo.apiVersion = VK_API_VERSION_1_0;
	appInfo.pEngineName = "No Engine";
	appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
	uint32_t glfwExtensionCount;
	// glfwGetRequiredInstanceExtensions获取Vulkan实例所需的扩展
	const	char** glfwExtensions;
	glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
	std::vector<const char*> Extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
	if (enabledValidationLayer) {
		// VK_EXT_DEBUG_UTILS_EXTENSION_NAME用于启用VK_EXT_debug_utils扩展，用于提供一些强大的调试工具
		Extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
	}
	// VkInstanceCreateInfo是用于创建VkInstance对象时提供的详细信息的结构体
	// sType 结构体标识
	// pApplicationInfo 指向VkApplicationInfo结构体的指针
	// enabledExtensionCount 启用的Vulkan扩展数量
	// ppEnabledExtensionNames 指向启用的Vulkan扩展名称的数组
	VkInstanceCreateInfo createInfo{};
	createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
	createInfo.pApplicationInfo = &appInfo;
	createInfo.enabledExtensionCount = Extensions.size();
	createInfo.ppEnabledExtensionNames = Extensions.data();
	if (enabledValidationLayer) {
		VkDebugUtilsMessengerCreateInfoEXT createInfoEXT;
		createInfo.enabledLayerCount = LayerNames.size();
		createInfo.ppEnabledLayerNames = LayerNames.data();
		populateDebugUtilsMessengerCreateInfo(createInfoEXT);
		createInfo.pNext = (PFN_vkCreateDebugUtilsMessengerEXT*)&createInfoEXT;
	}
	else {
		createInfo.enabledLayerCount = 0;
		createInfo.ppEnabledLayerNames = nullptr;
	}
	VkResult results;
	// vkCreateInstance是用于创建VkInstance对象的函数
	if ((results = vkCreateInstance(&createInfo, nullptr, &(this->instance))) != VK_SUCCESS) {
		switch (results) {
			// VK_ERROR_INCOMPATIBLE_DRIVER表示你的图像驱动与Vulkan版本或所需的Vulkan特性不兼容
		case VK_ERROR_INCOMPATIBLE_DRIVER:
			std::cout << "Driver didn`t support Vulkan!" << std::endl;
			break;
			// VK_ERROR_EXTENSION_NOT_PRESENT表示你请求的某个Vulkan扩展在当前的驱动程序或硬件上不可用
		case VK_ERROR_EXTENSION_NOT_PRESENT:
			std::cout << "Vulkan couldn`t support extensions your provided!" << std::endl;
			break;
		default:
			std::cout << "Unknown Error!" << std::endl;
		}
		throw std::runtime_error("Failed to create instance!");
	}
	for (int i = 0; i < glfwExtensionCount; ++i) {
		std::cout << *(glfwExtensions + i) << std::endl;
	}
}

bool test::checkValidationLayerSupport() {
	uint32_t availableLayerCount;
	// vkEnumerateInstanceLayerProperties用于查询可用实例层的一种函数
	vkEnumerateInstanceLayerProperties(&availableLayerCount, nullptr);
	// VkLayerProperties用于描述实例层属性的一个数据结构体
	std::vector<VkLayerProperties> availableLayerProperties(availableLayerCount);
	vkEnumerateInstanceLayerProperties(&availableLayerCount, availableLayerProperties.data());
	for (const char* LayerName : LayerNames) {
		bool layerFound = false;
		for (const auto& layerProperty : availableLayerProperties) {
			// str1 < str2 负值 str1 > str2 正值 str1 == str2 0
			if (strcmp(LayerName, layerProperty.layerName) == 0) {
				layerFound = true;
				break;
			}
		}
		if (!layerFound) {
			return false;
		}
	}
	return true;
}

void test::setupMessenger(){
	if (!enabledValidationLayer) {
		return;
	}
	VkDebugUtilsMessengerCreateInfoEXT createInfo;
	populateDebugUtilsMessengerCreateInfo(createInfo);
	if (createDebugUtilsMessenger(this->instance, &createInfo, nullptr, &this->debugMessenger) != VK_SUCCESS) {
		throw std::runtime_error("Failed to create debug utils messengers!");
	}
}

void test::populateDebugUtilsMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& debugUtilsMessenger){
	debugUtilsMessenger = {};
	debugUtilsMessenger.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
	// VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT 表示详细信息，通常用于开发过程中
	// VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT 表示信息性消息
	// VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT 表示警告信息
	// VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT 表示错误信息
	debugUtilsMessenger.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
		VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
		VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
	// VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT 一般性消息
	// VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT 验证层消息，表示Vulkan驱动和应用程序间的交互是否符合规范
	// VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT 性能相关的消息，表示某些操作可能导致性能问题
	debugUtilsMessenger.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
		VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT |
		VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
	debugUtilsMessenger.pfnUserCallback = test::debugCallback;
	debugUtilsMessenger.pUserData = nullptr;
}

VkResult test::createDebugUtilsMessenger(
	VkInstance c_instance, 
	VkDebugUtilsMessengerCreateInfoEXT* c_createInfo, 
	VkAllocationCallbacks* c_allocation, 
	VkDebugUtilsMessengerEXT* c_debugMessenger)
{
	// vkGetInstanceProcAddr用于查询Vulkan实例相关的扩展和函数指针，程序可以在运行时动态加载和调用Vulkan函数，而不是在编译时链接静态库
	auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(c_instance, "vkCreateDebugUtilsMessengerEXT");
	if (func != nullptr) {
		return func(c_instance, c_createInfo, c_allocation, c_debugMessenger);
	}
	else {
		return VK_ERROR_EXTENSION_NOT_PRESENT;
	}
}

void test::destroyDebugUtilsMessenger(VkInstance c_instance, VkDebugUtilsMessengerEXT c_debugMessenger, VkAllocationCallbacks* c_allocation)
{
	auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(c_instance, "vkDestroyDebugUtilsMessengerEXT");
	if (func != nullptr) {
		func(c_instance, c_debugMessenger, c_allocation);
	}
}

void test::pickupPhysicalDevice()
{
	uint32_t deviceCount;
	// vkEnumeratePhysicalDevices用于查询系统上可用的物理设备（GPU）函数
	vkEnumeratePhysicalDevices(this->instance, &deviceCount, nullptr);
	if (deviceCount == 0) {
		throw std::runtime_error("Failed to enumerate physical devices!");
	}
	std::vector<VkPhysicalDevice> devices(deviceCount);
	vkEnumeratePhysicalDevices(this->instance, &deviceCount, devices.data());

	for (const auto& physicalDevice : devices) {
		if (isDeviceSuitable(physicalDevice)) {
			this->device = physicalDevice;
			break;
		}
	}
	if (this->device == nullptr) {
		throw std::runtime_error("None of devices is suitable!");
	}
}

void test::createSurface()
{
	// glfwCreateWindowSurface是GLFW库的函数，用于在使用Vulkan渲染时创建一个与特定窗口相关的Vulkan表面
	if (glfwCreateWindowSurface(this->instance, this->window, nullptr, &this->surface) != VK_SUCCESS) {
		throw std::runtime_error("Failed to create Surface_KHR!");
	}
}

queueFamily test::findQueueFamilyIndex(VkPhysicalDevice c_device)
{
	uint32_t queueFamiliesCount;
	// vkGetPhysicalDeviceQueueFamilyProperties用于查询物理设备（GPU）支持的队列族的属性
	vkGetPhysicalDeviceQueueFamilyProperties(c_device, &queueFamiliesCount, nullptr);
	// VkQueueFamilyProperties用于描述队列族的属性
	// queueFlags 表示该队列族支持的命令类型，
	// VK_QUEUE_GRAPHICS_BIT（表示该队列族支持图形渲染命令（如绘制、着色器执行等））、
	// VK_QUEUE_COMPUTE_BIT（表示该队列族支持计算命令（如计算着色器））、
	// VK_QUEUE_SPARSE_BINDING_BIT（表示该队列族支持稀疏内存绑定（用于大内存页面的管理））、
	// VK_QUEUE_PROTECTED_BIT（表示该队列族支持保护模式队列（用于保护敏感数据的安全性））
	// queueCount 表示该队列族中队列的数量
	// timestampValidBits 表示该队列族支持的时间戳的有效位数
	// minImageTransferGranularity 表示该队列族执行图像传输操作时，允许传输的最小图像区域
	std::vector<VkQueueFamilyProperties> queueFamilies(queueFamiliesCount);
	vkGetPhysicalDeviceQueueFamilyProperties(c_device, &queueFamiliesCount, queueFamilies.data());
	int index = 0;
	queueFamily foundQueueFamily;
	for (const auto& QF : queueFamilies) {
		if (QF.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
			foundQueueFamily.graphicsQueueFamily = index;
		}
		VkBool32 presentSupported = false;
		// vkGetPhysicalDeviceSurfaceSupportKHR用于查询物理设备是否支持给定表面的图像呈现功能的函数
		vkGetPhysicalDeviceSurfaceSupportKHR(c_device, index, this->surface, &presentSupported);
		if (presentSupported) {
			foundQueueFamily.presentQueueFamily = index;
		}
		if (foundQueueFamily.isComplete()) {
			break;
		}
		index++;
	}
	return foundQueueFamily;
}

void test::createLogicDevice() 
{
	std::set<uint32_t> indices = {this->q_Family.graphicsQueueFamily.value(), this->q_Family.presentQueueFamily.value()};
	float queuePriorities = 1.f;
	std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
	for (uint32_t index : indices) {
		// VkDeviceQueueCreateInfo表示创建逻辑设备时有关队列的信息
		// sType 结构体标识
		// queueFamilyIndex 表示该队列所属的队列族的索引
		// queueCount 表示为该队列族所要创建的队列的数量
		// pQueuePriorities 指向队列优先级数组的指针
		VkDeviceQueueCreateInfo queueCreateInfo{};
		queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
		queueCreateInfo.queueFamilyIndex = index;
		queueCreateInfo.queueCount = 1;
		queueCreateInfo.pQueuePriorities = &queuePriorities;
		queueCreateInfos.push_back(queueCreateInfo);
	}
	VkPhysicalDeviceFeatures features{};
	// VkDeviceCreateInfo用于创建逻辑设备的结构体
	// sType 结构体标识
	// queueCreateInfoCount 表示被创建的队列族的数量
	// pQueueCreateInfos 指向VkDeviceQueueCreateInfo结构体数组的指针
	// enabledLayerCount 启用的验证层数量
	// ppEnabledLayerNames 指向启用的验证层[名称字符串数组的指针
	// enabledExtensionCount 启用的设备扩展数量
	// ppEnabledExtensionNames 指向启用的设备扩展名称字符串数组的指针
	// pEnabledFeatures 指向VkPhysicalDeviceFeatures结构体的指针，该结构体定义了物理设备（GPU）的特性
	VkDeviceCreateInfo createInfo{};
	createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
	createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
	createInfo.pQueueCreateInfos = queueCreateInfos.data();
	createInfo.pEnabledFeatures = &features;
	createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
	createInfo.ppEnabledExtensionNames = deviceExtensions.data();
	// vkCreateDevice用于创建逻辑设备的函数
	if (vkCreateDevice(this->device, &createInfo, nullptr, &this->logicDevice) !=VK_SUCCESS) { 
		throw std::runtime_error("Failed to create logic device!");
	}
	// vkGetDeviceQueue用于获取队列的函数
	vkGetDeviceQueue(this->logicDevice, this->q_Family.graphicsQueueFamily.value(), 0, &this->graphicsQueue);
	vkGetDeviceQueue(this->logicDevice, this->q_Family.presentQueueFamily.value(), 0, &this->presentQueue);
}

bool test::isDeviceSuitable(VkPhysicalDevice c_device) 
{
	// VkPhysicalDeviceProperties包含物理设备（GPU）基本信息的结构体，如设备名称、硬件版本、驱动程序版本
	// sType 结构体标识
	// pNext 链式扩展指针
	// apiVersion Vulkan API版本
	// driverVersion 驱动程序的版本
	// vendorID 硬件厂商的ID
	// deviceID 设备的ID
	// deviceType 设备类型，表示设备的类型，VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU（独立显卡）、VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU（集成显卡）、
	// VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU（虚拟 GPU）、VK_PHYSICAL_DEVICE_TYPE_CPU（CPU）、VK_PHYSICAL_DEVICE_TYPE_OTHER（其他类型的设备）
	// deviceName 设备的名称
	// pipelineCacheUUID 管线缓存的UUID
	// limits 设备支持的硬件限制
	// sparseProperties 描述设备对洗漱资源的支持
	VkPhysicalDeviceProperties deviceProperties;
	// VkPhysicalDeviceFeatures用于描述物理设备（GPU）所支持的特性
	// robustBufferAccess 是否支持强健的缓冲区访问
	// fullDrawIndexUint32 是否支持完整的绘制索引 uint32
	// imageCubeArray 是否支持图像立方体数组
	// independentBlend 是否支持独立混合
	// geometryShader 是否支持几何着色器
	// tessellationShader 是否支持细分着色器
	// sampleRateShading 是否支持采样率着色
	// dualSrcBlend 是否支持双源混合
	// logicOp 是否支持逻辑操作
	// multiDrawIndirect 是否支持多重间接绘制
	// drawIndirectFirstInstance 是否支持间接绘制的第一次实例
	// depthClamp 是否支持深度夹取
	// depthBiasClamp 是否支持深度偏移夹取
	// fillModeNonSolid 是否支持非实心填充模式
	// depthBounds 是否支持深度范围
	// wideLines 是否支持宽线段
	// largePoints 是否支持大点
	// alphaToOne 是否支持alpha到1
	// multiViewport 是否支持多视口
	// samplerAnisotropy 是否支持采样器各向异性
	// textureCompressionETC2 是否支持 ETC2 纹理压缩
	// textureCompressionASTC_LDR 是否支持 ASTC LDR 纹理压缩
	// textureCompressionBC 是否支持 BC 纹理压缩
	// occlusionQueryPrecise 是否支持精确的遮挡查询
	// pipelineStatisticsQuery 是否支持管线统计查询
	// vertexPipelineStoresAndAtomics 是否支持顶点管线存储和原子操作
	// fragmentStoresAndAtomics 是否支持片段管线存储和原子操作
	// shaderTessellationAndGeometryPointSize 是否支持着色器细分与几何点大小
	// textureCompressionETC2 是否支持 ETC2 纹理压缩
	// robustImageAccess 是否支持强健的图像访问
	// fullDrawIndexUint32 是否支持完整的绘制索引 uint32
	// imageCubeArray 是否支持图像立方体数组
	// independentBlend 是否支持独立混合
	VkPhysicalDeviceFeatures deviceFeatures;
	// vkGetPhysicalDeviceProperties用于获取指定物理设备（GPU）的硬件属性
	vkGetPhysicalDeviceProperties(c_device, &deviceProperties);
	// vkGetPhysicalDeviceFeatures用于查询给定物理设备（GPU）支持的特性
	vkGetPhysicalDeviceFeatures(c_device, &deviceFeatures);
	this->q_Family = findQueueFamilyIndex(c_device);
	bool deviceExtensionSupported = checkDeviceExtensionSupported(c_device);
	bool swapChainAdequate = false;
	if (deviceExtensionSupported) {
		SwapChainDetails detail = querySwapChainSupport(c_device);
		swapChainAdequate = !detail.formats.empty() && !detail.modes.empty();
	}
	return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && 
		deviceFeatures.geometryShader && 
		q_Family.isComplete() && 
		deviceExtensionSupported && 
		swapChainAdequate;
}

bool test::checkDeviceExtensionSupported(VkPhysicalDevice c_device)
{
	uint32_t deviceExtensionCount;
	// vkEnumerateDeviceExtensionProperties用于查询指定物理设备（GPU）支持的扩展列表
	vkEnumerateDeviceExtensionProperties(c_device, nullptr, &deviceExtensionCount, nullptr);
	// VkExtensionProperties用于描述扩展信息的结构体
	// extensionName 扩展的名称
	// specVersion 扩展的版本
	std::vector<VkExtensionProperties> availableExtensions(deviceExtensionCount);
	vkEnumerateDeviceExtensionProperties(c_device, nullptr, &deviceExtensionCount, availableExtensions.data());
	std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
	for (const auto& Extension : availableExtensions) {
		requiredExtensions.erase(Extension.extensionName);
	}
	return requiredExtensions.empty();
}

SwapChainDetails test::querySwapChainSupport(VkPhysicalDevice c_device)
{
	SwapChainDetails details;
	details.cap = GetSurfaceCap(c_device);
	details.formats = GetSurfaceFmt(c_device);
	details.modes = GetSurfacePM(c_device);
	return details;
}

VkSurfaceCapabilitiesKHR test::GetSurfaceCap(VkPhysicalDevice c_device)
{
	VkSurfaceCapabilitiesKHR SurCap;
	// vkGetPhysicalDeviceSurfaceCapabilitiesKHR用于查询指定物理设备和表面的能力
	vkGetPhysicalDeviceSurfaceCapabilitiesKHR(c_device, this->surface, &SurCap);
	return SurCap;
}

std::vector<VkSurfaceFormatKHR> test::GetSurfaceFmt(VkPhysicalDevice c_device)
{
	std::vector<VkSurfaceFormatKHR> SurFmt{};
	uint32_t FmtCount;
	// vkGetPhysicalDeviceSurfaceFormatsKHR用于查询物理设备支持的表面格式
	vkGetPhysicalDeviceSurfaceFormatsKHR(c_device, this->surface, &FmtCount, nullptr);
	if (FmtCount != 0) {
		SurFmt.resize(FmtCount);
		vkGetPhysicalDeviceSurfaceFormatsKHR(c_device, this->surface, &FmtCount, SurFmt.data());
	}
	return SurFmt;
}

std::vector<VkPresentModeKHR> test::GetSurfacePM(VkPhysicalDevice c_device)
{
	std::vector<VkPresentModeKHR> PModes{};
	uint32_t PModeCount;
	// vkGetPhysicalDeviceSurfacePresentModesKHR用于查询物理设备支持的表面呈现模式
	vkGetPhysicalDeviceSurfacePresentModesKHR(c_device, this->surface, &PModeCount, nullptr);
	if (PModeCount != 0) {
		PModes.resize(PModeCount);
		vkGetPhysicalDeviceSurfacePresentModesKHR(c_device, this->surface, &PModeCount, PModes.data());
	}
	return PModes;
}

VkSurfaceFormatKHR test::chooseSurfaceFmt(const SwapChainDetails& details)
{
	const std::vector<VkSurfaceFormatKHR>& availableFormats = details.formats;
	for (const auto& availableFormat : availableFormats) {
		if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
			return availableFormat;
		}
	}
	return availableFormats[0];
}

VkPresentModeKHR test::choosePresentMode(const SwapChainDetails& details)
{
	const std::vector<VkPresentModeKHR>& availablePresentModes = details.modes;
	for (const auto& availablePresentMode : availablePresentModes) {
		if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
			return availablePresentMode;
		}
	}
	return VK_PRESENT_MODE_FIFO_KHR;
}

VkExtent2D test::chooseExtent2D(const SwapChainDetails& details)
{
	const VkSurfaceCapabilitiesKHR& capabilities = details.cap;
	// std::numeric_limit是C++模板类，提供有关算数类型属性的信息
	if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
		return capabilities.currentExtent;
	}
	else {
		int width, height;
		// glfwGetFramebufferSize是GLFW库的函数，用于获取窗口的帧缓冲大小
		glfwGetFramebufferSize(this->window, &width, &height);
		VkExtent2D actualExtent = {
			static_cast<uint32_t>(width), 
			static_cast<uint32_t>(height)
		};
		actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
		actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.width, capabilities.maxImageExtent.height);
		return actualExtent;
	}
}

void test::createSwapChain()
{
	SwapChainDetails details = querySwapChainSupport(this->device);
	VkSurfaceFormatKHR surfaceFormat = chooseSurfaceFmt(details);
	VkPresentModeKHR presentMode = choosePresentMode(details);
	VkExtent2D extent = chooseExtent2D(details);
	uint32_t imageCount = details.cap.minImageCount + 1;
	if (details.cap.maxImageCount > 0 && imageCount > details.cap.maxImageCount) {
		imageCount = details.cap.maxImageCount;
	}
	// VkSwapchainCreateInfoKHR用于创建交换链的结构体
	// sType 结构体标识
	// surface 关联的表面句柄
	// minImageCount 交换链中图像的最小数量
	// imageFormat 图像的格式
	// imageColorSpace 交换链图像的颜色空间
	// imageExtent 图像的大小
	// imageArrayLayers 图像的层数
	// imageUsage图像的用途
	// imageSharingMode 图像共享模式，关联queueFamilyIndexCount、pQueueFamilyIndices
	// queueFamilyIndexCount 队列族的数量
	// pQueueFamilyIndices 队列族索引数组
	// preTransform 表示交换链图像需要经过的任何预变换
	// compositeAlpha 控制透明度合成的选项
	// presentMode 呈现模式
	// clipped 是否启用剪裁
	// oldSwapchain 旧的交换链
	VkSwapchainCreateInfoKHR createInfo{};
	createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
	createInfo.surface = this->surface;
	createInfo.minImageCount = imageCount;
	createInfo.imageFormat = surfaceFormat.format;
	createInfo.imageColorSpace = surfaceFormat.colorSpace;
	createInfo.imageExtent = extent;
	createInfo.imageArrayLayers = 1;
	createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
	queueFamily q_F = findQueueFamilyIndex(this->device);
	uint32_t queueFamilyIndices[] = {q_F.graphicsQueueFamily.value(), q_F.presentQueueFamily.value()};
	if (q_F.graphicsQueueFamily != q_F.presentQueueFamily) {
		createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
		createInfo.queueFamilyIndexCount = 2;
		createInfo.pQueueFamilyIndices = queueFamilyIndices;
	}
	else {
		createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
		createInfo.queueFamilyIndexCount = 0;
		createInfo.pQueueFamilyIndices = nullptr;
	}
	createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
	createInfo.preTransform = details.cap.currentTransform;
	createInfo.clipped = VK_TRUE;
	createInfo.oldSwapchain = VK_NULL_HANDLE;
	// vkCreateSwapchainKHR用于创建交换链的函数
	if (vkCreateSwapchainKHR(this->logicDevice, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
		throw std::runtime_error("Failed to create swap chain!");
	}
	this->swapChainImageFormat = surfaceFormat.format;
	this->swapChainImageExtent = extent;
}

void test::GetSwapChainImage(std::vector<VkImage>& images)
{
	uint32_t imageCount;
	// vkGetSwapchainImagesKHR用来获取与交换链相关的所有图像
	vkGetSwapchainImagesKHR(this->logicDevice, this->swapChain, &imageCount, nullptr);
	if (imageCount != 0) {
		images.resize(imageCount);
		vkGetSwapchainImagesKHR(this->logicDevice, this->swapChain, &imageCount, images.data());
	}
}

void test::createImageView()
{
	imageViews.resize(this->swapChainImages.size());
	for (int index = 0; index < imageViews.size(); index++) {
		// VkImageViewCreateInfo用于创建图像视图的结构体，指定如何访问和解释图像数据
		// sType 结构体标识
		// image 关联的图像
		// viewType 图像视图类型
		// VK_IMAGE_VIEW_TYPE_1D（视图类型用于访问一维图像数据）、VK_IMAGE_VIEW_TYPE_2D（视图类型用于访问二维图像数据）、
		// VK_IMAGE_VIEW_TYPE_3D（视图类型用于访问三维图像数据）、VK_IMAGE_VIEW_TYPE_CUBE（视图类型用于访问立方体图像数据）、
		// VK_IMAGE_VIEW_TYPE_1D_ARRAY（视图类型用于访问一维图像数组）、VK_IMAGE_VIEW_TYPE_2D_ARRAY（视图类型用于访问二维图像数组）、
		// VK_IMAGE_VIEW_TYPE_CUBE_ARRAY（视图类型用于访问立方体图像数组）
		// format 图像格式
		// components 颜色组件映射，指定如何访问图像的颜色通道
		// VK_COMPONENT_SWIZZLE_IDENTITY（表示图像的颜色分量不会被修改，直接使用原始的颜色通道数据）、
		// VK_COMPONENT_SWIZZLE_ZERO（将颜色分量映射到零值，无论源图像中的通道是什么，都会将其映射为0）、
		// VK_COMPONENT_SWIZZLE_ONE（将颜色分量映射为常数1，这通常用于保持一个颜色通道常为1）、
		// VK_COMPONENT_SWIZZLE_R、VK_COMPONENT_SWIZZLE_G、VK_COMPONENT_SWIZZLE_B、VK_COMPONENT_SWIZZLE_A（这些值分别表示将颜色分量映射到源图像的相应颜色通道）
		// subresourceRange 描述图像视图所访问的图像的子资源范围
		// aspectMask 指定你要访问的图像的哪些“方面”
		// VK_IMAGE_ASPECT_COLOR_BIT（访问图像的颜色通道）、VK_IMAGE_ASPECT_DEPTH_BIT（访问图像的深度通道）、
		// VK_IMAGE_ASPECT_STENCIL_BIT（访问图像的模板通道）、VK_IMAGE_ASPECT_METADATA_BIT（访问图像的元数据）
		// baseMipLevel 指定你要访问的mipmap层级的起始层级
		// levelCount 指定要访问的mipmap层级的数量
		// baseArrayLayer 指定图像数组的起始层级
		// layerCount 指定要访问的图像数组层级的数量
		VkImageViewCreateInfo createInfo{};
		createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
		createInfo.image = this->swapChainImages[index];
		createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
		createInfo.format = this->swapChainImageFormat;
		createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
		createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
		createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
		createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
		createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
		createInfo.subresourceRange.baseMipLevel = 0;
		createInfo.subresourceRange.levelCount = 1;
		createInfo.subresourceRange.baseArrayLayer = 0;
		createInfo.subresourceRange.layerCount = 1;
		// vkCreateImageView用于创建一个图像对象的函数
		if (vkCreateImageView(this->logicDevice, &createInfo, nullptr, &this->imageViews[index]) != VK_SUCCESS) {
			throw std::runtime_error("Failed to create image view!");
		}
	}
}

void test::createRenderPass()
{
	// VkAttachmentDescription用于定义渲染通道附件的相关属性的结构体
	// flags 附件的标志，控制附件的附加属性
	// VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS（指示该附件可能与其他附件共享内存）、
	// VK_ATTACHMENT_DESCRIPTION_BLIT_SRC（指示附件可以用作VkCmdBlitImage的源）
	// VK_ATTACHMENT_DESCRIPTION_BLIT_DST（指示附件可以用作VkCmdBlitImage的目标）
	// format 附件的像素格式
	// semples 表示附件的样本数
	// loadOp 在渲染开始时如何加载附件的数据
	// VK_ATTACHMENT_LOAD_OP_LOAD（保留附件的现有内容）、VK_ATTACHMENT_LOAD_OP_CLEAR（清空附件并用一个指定的值填充）、
	// VK_ATTACHMENT_LOAD_OP_DONT_CARE（不关心附件的当前内容）
	// storeOp 渲染完成后如何处理附件的数据
	// VK_ATTACHMENT_STORE_OP_STORE（存储渲染结果）、VK_ATTACHMENT_STORE_OP_DONT_CARE（渲染结束后不关心附件的内容）
	// stencilLoadOp、stencilStoreOp 仅对模板缓冲有效，用于指定模板缓冲区的加载和存储操作
	// initialLayout 附件在渲染通道开始时的初始图像布局
	// VK_IMAGE_LAYOUT_UNDEFINED（表示该附件的初始状态不确定，可能是一个未初始化的图像）、
	// VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL（当附件用作颜色附件时，通常会选择此布局）
	// finalLayout 指定渲染结束后，附件的最终布局
	// VK_IMAGE_LAYOUT_PRESENT_SRC_KHR（当渲染结果准备好显示到屏幕时，使用此布局）、
	// VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL（当渲染结束后图像仍用作颜色附件时使用）、
	// VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL（如果图像需要用于着色器采样时（例如，作为纹理）使用）
	VkAttachmentDescription colorAttachmentDescription{};
	colorAttachmentDescription.flags = 0;
	colorAttachmentDescription.format = this->swapChainImageFormat;
	colorAttachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT;
	colorAttachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
	colorAttachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
	colorAttachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
	colorAttachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
	colorAttachmentDescription.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
	colorAttachmentDescription.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
	// VkAttachmentReference用于描述渲染通道中附件绑定方式的结构体
	// attachment 渲染通道中附件的索引
	// layout 指定该附件在渲染通道期间应处于的图像布局
	// VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL（用于颜色附件）
	// VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL（用于深度/模板附件）
	// VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL（用于着色器只读附件）
	VkAttachmentReference colorAttachmentRef{};
	colorAttachmentRef.attachment = 0;
	colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
	// VkSubpassDescription用于描述渲染通道中单个子通道的操作的结构体
	// 子通道是渲染过程中的一个基本单位，用于描述在渲染过程中，如何对图像附件进行一系列的操作
	// pipelineBindPoint 指定渲染管线绑定点类型，通常设置为VK_PIPELINE_BIND_POINT_GRAPHICS，表示图形管线，也可以是VK_PIPELINE_BIND_POINT_COMPUTE，表示计算管线
	// colorAttachmentCount 表示颜色附件的数量
	// pColorAttachments 指向颜色附件数组的指针，每个元素是VkAttachmentReference，表示颜色附件的索引和访问布局
	VkSubpassDescription subpassDescription{};
	subpassDescription.flags = 0;
	subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
	subpassDescription.colorAttachmentCount = 1;
	subpassDescription.pColorAttachments = &colorAttachmentRef;
	// VkSubpassDependency用于定义渲染通道中不同子通道之间的依赖关系，可以了解子通道之间的资源访问顺序，确保在渲染过程中正确的同步和资源管理
	// srcSubpass 指定源子通道的索引，源子通道是依赖的起点，通常是数据的生产者，VK_SUBPASS_EXTERNAL可用于表示外部子通道（例如，渲染通道之前的操作）
	// srcStageMask 定义源子通道必须完成的管道阶段，管道阶段是指GPU执行操作的不同阶段，这些字段控制源子通道在执行时必须经历哪些管道阶段才能触发子通道依赖
	// VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT（颜色附件输出阶段）、VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT（片段着色器阶段）、
	// VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT（计算着色器阶段）、VK_PIPELINE_STAGE_TRANSFER_BIT（传输阶段）、VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT（管道底部阶段，表示依赖关系的终结点）
	// srcAccessMask 定义源子通道对资源（如图像、缓冲区）的访问权限，描述了源子通道对数据的“读”或“写”操作
	// VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT（源子通道写入颜色附件）、VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT（源子通道写入深度或模板附件）、
	// VK_ACCESS_SHADER_READ_BIT（源子通道的着色器读取操作）、VK_ACCESS_TRANSFER_READ_BIT（源子通道的传输读取操作）、VK_ACCESS_MEMORY_READ_BIT（源子通道对内存的读取操作）
	// dstSubpass 指定目标子通道的索引，目标子通道是依赖的终点，通常是数据的消费者，VK_SUBPASS_EXTERNAL同样可以表示外部子通道（例如，渲染通道之后的操作）
	// dstStageMask 定义目标子通道需要在执行时等待的管道阶段，目标子通道必须等待源子通道中的特定阶段完成才能继续执行
	// dstAccessMask 定义目标子通道对资源的访问权限，描述了目标子通道对数据的“读”或“写”操作
	// VK_ACCESS_COLOR_ATTACHMENT_READ_BIT（目标子通道读取颜色附件）、VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT（目标子通道读取深度或模板附件）、
	// VK_ACCESS_SHADER_WRITE_BIT（目标子通道写入操作，如着色器的写操作）、VK_ACCESS_TRANSFER_WRITE_BIT（目标子通道的传输写操作）、VK_ACCESS_MEMORY_WRITE_BIT（目标子通道对内存的写入操作）、
	// VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT（目标子通道写入颜色附件操作）
	VkSubpassDependency subpassDependency{};
	subpassDependency.srcSubpass = VK_SUBPASS_EXTERNAL;
	subpassDependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
	subpassDependency.srcAccessMask = 0;
	subpassDependency.dstSubpass = 0;
	subpassDependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
	subpassDependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
	// VkRenderPassCreateInfo用于创建渲染通道的结构体
	// sType 结构体标识
	// attachmentCount 表示附件的数量
	// pAttachments 指向VkAttachmentDescription数组的指针
	// subpassCount 表示子通道的数量
	// pSubpasses 指向VkSubpassDescription数组的指针
	// dependencyCount 渲染通道中的依赖关系数量，依赖关系描述了不同子通道之间的同步要求，确保子通道按正确的顺序执行
	// pDependencies 指向VkSubpassDependency数组的指针，用于描述子通道之间的依赖关系，通过这些依赖关系，确保在执行一个子通道之前，另一个子通道的相关操作已经完成
	VkRenderPassCreateInfo createInfo{};
	createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
	createInfo.attachmentCount = 1;
	createInfo.pAttachments = &colorAttachmentDescription;
	createInfo.subpassCount = 1;
	createInfo.pSubpasses = &subpassDescription;
	createInfo.dependencyCount = 1;
	createInfo.pDependencies = &subpassDependency;
	if (vkCreateRenderPass(this->logicDevice, &createInfo, nullptr, &this->renderPass) != VK_SUCCESS) {
		throw std::runtime_error("Failed to create render pass!");
	}
}

void test::createGraphicsPipeline()
{
	std::vector<char> vertexCode = readFile("Shader/vert.spv");
	std::vector<char> fragmentCode = readFile("Shader/frag.spv");
	VkShaderModule vertexShaderModule = createShaderModule(vertexCode);
	VkShaderModule fragmentShaderModule = createShaderModule(fragmentCode);
	// VkPipelineShaderStageCreateInfo描述管线阶段着色器的结构体，用于设置管线中各个着色器阶段
	// sType 结构体标识
	// stage 指定着色器的类型
	// VK_SHADER_STAGE_VERTEX_BIT（顶点着色器）、VK_SHADER_STAGE_FRAGMENT_BIT（片段着色器）、VK_SHADER_STAGE_COMPUTE_BIT（计算着色器）、
	// VK_SHADER_STAGE_GEOMETRY_BIT（几何着色器）、VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT（曲面细分控制着色器）、
	// VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT（曲面细分评估着色器）、VK_SHADER_STAGE_RAYGEN_BIT_KHR（光线生成着色器）
	// module 表示着色器程序的二进制代码
	// pName 着色器入口函数的名字
	// pSpecializationInfo 一个指向VkSpecializationInfo结构体的指针，用于着色器的特化常量
	VkPipelineShaderStageCreateInfo vertexStageInfo{};
	vertexStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
	vertexStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
	vertexStageInfo.module = vertexShaderModule;
	vertexStageInfo.pName = "main";
	VkPipelineShaderStageCreateInfo fragmentStageInfo{};
	fragmentStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
	fragmentStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
	fragmentStageInfo.module = fragmentShaderModule;
	fragmentStageInfo.pName = "main";
	VkPipelineShaderStageCreateInfo ShaderStageInfos[] = {vertexStageInfo, fragmentStageInfo};
	// 固定功能状态
	// 1、输入汇编器（Input Assembler）；顶点数据到图元的“组装工厂”
	// VkPipelineVertexInputStateCreateInfo用于描述图形管线中顶点输入阶段的结构体
	// sType 结构体标识
	// vertexBindingDescriptionCount 顶点绑定描述符的数量
	// pVertexBindingDescriptions 指向VkVertexInputBindingDescription结构体数组的指针
	// - VkVertexInputBindingDescription用于描述顶点缓冲区绑定的结构体
	// - binding 顶点缓冲区的绑定点索引，用于标识该缓冲区，与layout(binding = N)配对，就是读取的数据的索引
	// - stride 顶点数据的补偿，即每个顶点的字节大小
	// - inputRate 数据传递给着色器的速率
	// - VK_VERTEX_INPUT_RATE_VERTEX（每个顶点传递一次数据，每个顶点在每次绘制调用时会从缓冲区读取一行数据）、
	// - VK_VERTEX_INPUT_RATE_INSTANCE（每个实例传递一次数据，这通常用于实例化渲染）
	// vertexAttributeDescriptionCount 顶点属性描述符的数量
	// pVertexAttributeDescriptions 指向VkVertexInputAttributeDescription结构体数组的指针
	// - VkVertexInputAttributeDescription用于描述顶点缓冲区中单个顶点属性的结构体
	// - location 顶点属性的位置标识符，着色器中定义的layout(location = N)相匹配
	// - binding 顶点缓冲区的绑定点索引
	// - format 顶点属性的数据格式
	// - VK_FORMAT_R32G32B32_SFLOAT（表示包含3个32位浮点数的属性（如3D位置））
	// - VK_FORMAT_R32G32_SFLOAT（表示包含2个32 位浮点数的属性（如2D纹理坐标））
	// - VK_FORMAT_R8G8B8A8_UNORM（表示4个8位无符号整型数的属性（如颜色））
	// - offset 顶点属性在缓冲区中的偏移量
	VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
	vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
	vertexInputInfo.vertexBindingDescriptionCount = 0;
	vertexInputInfo.pVertexBindingDescriptions = nullptr;
	vertexInputInfo.vertexAttributeDescriptionCount = 0;
	vertexInputInfo.pVertexAttributeDescriptions = nullptr;
	// VkPipelineInputAssemblyStateCreateInfo是渲染管线中的输入汇编阶段的配置结构体，定义了如何从顶点数据中构建图形原语（如三角形、线段等）
	// sType 结构体标识
	// topology 指定要生成的几何图形原语类型
	// VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST（三角形列表（每3个顶点组成一个三角形））、VK_PRIMITIVE_TOPOLOGY_LINE_LIST（线段列表（每2个顶点组成一条线段））、
	// VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP（三角形带（多个三角形共享边，按顺序组装））、VK_PRIMITIVE_TOPOLOGY_POINT_LIST（点列表（每个顶点作为一个点））
	// primitiveRestarEnable 指定是否启用原语重启，启用原语重启后，当索引缓冲区中遇到一个特定的重启索引值（例如：0xFFFF），会认为当前图形原语结束，并开始新的图形原语
	VkPipelineInputAssemblyStateCreateInfo assemblyInfo{};
	assemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
	assemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
	assemblyInfo.primitiveRestartEnable = VK_FALSE;
	// 2、视口与裁剪矩形（Viewport & Scissor）；渲染区域的“边界框”
	// VkViewport用于描述渲染管线的视口区域，指定了如何将三维世界的坐标转换为二维屏幕空间坐标
	// x,y 视口左下角的x,y坐标
	// width,height 视口的宽度和高度
	// minDepth,maxDepth 视口的最小和最大深度
	VkViewport viewport{};
	viewport.x = 0.f;
	viewport.y = 0.f;
	viewport.width = (float)this->swapChainImageExtent.width;
	viewport.height = (float)this->swapChainImageExtent.height;
	viewport.minDepth = 0.f;
	viewport.maxDepth = 1.f;
	// VkRect2D用于定义矩形区域的结构体，通常用于视口、剪辑区域、清除区域等场景
	// offset 用于定义矩形区域的左上角位置
	// extent 用于定义矩形区域的宽度和高度
	VkRect2D scissor{};
	scissor.offset = {0, 0};
	scissor.extent = this->swapChainImageExtent;
	// VkPipelineViewportStateCreateInfo用于描述视口与裁剪矩形状态的结构体
	// sType 结构体标识管线中使用的视口数量
	// viewportCount 指定管线中使用的视口数量
	// pViewport 指向Viewport数组，每个元素描述一个视口
	// scissorCount 指定裁剪矩形数量
	// pScissor 指向VkRect数组，每个元素描述一个裁剪矩形
	VkPipelineViewportStateCreateInfo viewportInfo{};
	viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
	viewportInfo.viewportCount = 1;
	viewportInfo.pViewports = &viewport;
	viewportInfo.scissorCount = 1;
	viewportInfo.pScissors = &scissor;
	// 3、光栅化器（Rasterizer）；三角形到片段的“离散器”
	// VkPipelineRasterizationStateCreateInfo用于指定光栅化状态，光栅化状态控制图形管线中光栅化阶段的行为
	// sType 结构体标识
	// depthClampEnable 设置是否启用深度夹持，深度夹持会将深度值限制在深度范围内，而不会被裁剪掉
	// rasterizerDiscardEnable 设置是否启用光栅化丢弃，启用该选项后，光栅化阶段会被完全跳过，渲染过程中将不会生成任何片段
	// polygonMode 定义多边形的填充方式
	// VK_POLYGON_MODE_FILL（填充模式（默认），即将多边形内填充像素）、
	// VK_POLYGON_MODE_LINE（线框模式，即将多边形的边界以线段形式绘制）、
	// VK_POLYGON_MODE_POINT（点模式，即仅绘制多边形的顶点）
	// lineWidth 用于定义绘制线段时的线宽，一般来说是1.f，如果非1.f需要物理设备（GPU）支持
	// cullMode 定义背面或前面是否被剔除
	// VK_CULL_MODE_NONE（不剔除任何面）、
	// VK_CULL_MODE_FRONT_BIT（剔除前面（即顺时针面））、
	// VK_CULL_MODE_BACK_BIT（剔除背面（即逆时针面））、
	// VK_CULL_MODE_FRONT_AND_BACK（剔除前后两面）
	// frontFace 定义前面朝向顺序，影响面剔除
	// VK_FRONT_FACE_CLOCKWISE（顺时针为正面）、
	// VK_FRONT_FACE_COUNTER_CLOCKWISE（逆时针为正面）
	// depthBiasEnable 设置是否启用深度偏移，深度偏移用于解决Z-fighting问题
	// depthBiasConstantFactor 定义深度偏移的常数因子，控制着深度偏移量的基准值，就是偏移要加减的值
	// depthBiasSlopeFactor 定义深度偏移的斜率因子，用于动态地计算深度偏移，通常根据多边形的斜率（角度）来确定深度偏移的量
	// depthBiasClamp 定义深度偏移的夹住值，表示深度偏移的最大值
	// FinalDepth = DepthAfterProjection + Sign × ( DepthBiasConstantFactor + DepthBiasSlopeFactor × Min ( FragmentDepth, MaxDepth ) )
	VkPipelineRasterizationStateCreateInfo rasterizationInfo{};
	rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
	rasterizationInfo.depthClampEnable = VK_FALSE;
	rasterizationInfo.rasterizerDiscardEnable = VK_FALSE;
	rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL;
	rasterizationInfo.lineWidth = 1.f;
	rasterizationInfo.cullMode = VK_CULL_MODE_BACK_BIT;
	rasterizationInfo.frontFace = VK_FRONT_FACE_CLOCKWISE;
	rasterizationInfo.depthBiasEnable = VK_FALSE;
	rasterizationInfo.depthBiasConstantFactor = 0.f;
	rasterizationInfo.depthBiasSlopeFactor = 0.f;
	rasterizationInfo.depthBiasClamp = 0.f;
	// 4、多重采样（Multisampling）：抗锯齿的“硬件加速器”
	// VkPipelineMultisampleStateCreateInfo用于描述渲染管线的多重采样的状态的结构体，定义管线在渲染过程中如何进行多重采样抗锯齿（MSAA）操作，以提升图像质量
	// sType 结构体标识
	// rasterizationSample 定义每个像素的采样数，表示多重采样的级别
	// VK_SAMPLE_COUNT_1_BIT（无多重采样（单一采样））、VK_SAMPLE_COUNT_2_BIT（2x多重采样）、
	// VK_SAMPLE_COUNT_4_BIT（4x多重采样）、VK_SAMPLE_COUNT_8_BIT（8x多重采样）、VK_SAMPLE_COUNT_16_BIT（16x多重采样）
	// sampleShadingEnable 控制是否启用样本着色，当启用时，光栅化的每个样本会根据样本的不同位置进行不同的颜色计算
	// minSampleShading 用于控制每个样本的最小着色率，当sampleShadingEnable为VK_TRUE时有效，这个是根据设置值来规定一个像素中至少有多少百分比的样本数量才能参与计算最终像素的颜色
	// pSampleMask 可选的掩码数组，用于指定哪些样本应该被考虑用于最终计算
	// alphaToCoverageEnable 启用或禁用Alpha到覆盖效果，这个根据alpha值来规定一个像素中至少有多少百分比的样本数量才能参与计算最终像素的颜色
	VkPipelineMultisampleStateCreateInfo multisampleInfo{};
	multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
	multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
	multisampleInfo.sampleShadingEnable = VK_FALSE;
	multisampleInfo.minSampleShading = 0.5f;
	multisampleInfo.pSampleMask = nullptr;
	multisampleInfo.alphaToCoverageEnable = VK_FALSE;
	// 5、深度与模板测试（Depth/Stencil Test）：可见性“裁判”
	// 深度测试是通过判断片元的深度值，决定哪些片元能够被显示出来，而哪些片元会被丢弃
	// 模板测试是通过判断片元的模板值，决定那些片元能够被渲染效果，而那些片元不会渲染
	// VkPipelineDepthStencilStateCreateInfo用于描述深度和模板测试状态的结构体
	// sType 结构体标识
	// depthTestEnable 设置是否启用深度测试，启用时，图形管线会使用深度缓冲来决定哪些片元应该被渲染
	// depthWriteEnable 设置是否启用深度写入，启用时，深度缓冲区的值会在片元渲染时被更新
	// depthCompareOp 深度比较操作，控制如何比较当前深度与已存储的深度值
	// VK_COMPARE_OP_LESS（如果当前深度值小于已存储的深度值，则通过深度测试）、VK_COMPARE_OP_LESS_OR_EQUAL（当前深度值小于或等于已存储的深度值）、
	// VK_COMPARE_OP_GREATER（当前深度值大于已存储的深度值）、VK_COMPARE_OP_EQUAL（当前深度值等于已存储的深度值）、VK_COMPARE_OP_NOT_EQUAL（当前深度值不等于已存储的深度值）、
	// VK_COMPARE_OP_ALWAYS（始终通过深度测试（最常用于不需要深度测试的情况））
	// depthBoundsTestEnable 是否启用深度范围测试，启用时，渲染的片元需要满足深度值在指定范围内才能通过测试
	// minDepthBounds和maxDepthBounds 定义了深度范围测试的最小和最大深度值，仅当启用depthBoundsTestEnable时才有效
	// stencilTestEnable 设置是否启用模板测试
	// front和back 描述了前面和后面面（即正面和背面）的模板操作
	// - VkStencilOpState用于描述模板操作的设置的结构体
	// - failOp和passOp 模板测试失败和通过时的操作
	// - depthFailOp 当片元通过模板测试但深度测试失败时的操作
	// - VK_STENCIL_OP_KEEP（保持当前模板值不变）、VK_STENCIL_OP_ZERO（将模板值设置为0）、VK_STENCIL_OP_REPLACE（将模板值替换为参考值）、
	// - VK_STENCIL_OP_INCREMENT（将模板值增加1（如果溢出则回绕））、VK_STENCIL_OP_DECREMENT（将模板值减少1（如果下溢则回绕））、
	// - VK_STENCIL_OP_INVERT（对模板值进行按位取反）
	// - compareOp 用于决定当前片元的模板值与模板缓冲区中的值如何比较
	// - VK_COMPARE_OP_NEVER（模板比较总是失败）、VK_COMPARE_OP_LESS（当前模板值小于模板缓冲区中的值时通过）、
	// - VK_COMPARE_OP_EQUAL（当前模板值等于模板缓冲区中的值时通过）、VK_COMPARE_OP_LESS_OR_EQUAL（当前模板值小于或等于模板缓冲区中的值时通过）、
	// - VK_COMPARE_OP_GREATER（当前模板值大于模板缓冲区中的值时通过）、VK_COMPARE_OP_NOT_EQUAL（当前模板值不等于模板缓冲区中的值时通过）、
	// - VK_COMPARE_OP_GREATER_OR_EQUAL（当前模板值大于或等于模板缓冲区中的值时通过）、VK_COMPARE_OP_ALWAYS（模板比较总是通过（用于不关心模板值的情况））
	// - reference 用于模板测试的参考值，模板值会与模板缓冲区中的值进行比较，这个参考值是希望进行比较的值
	// - compareMask 模板比较时的掩码，使用掩码来控制哪些位参与模板比较，掩码的每个1位都表示对应的模板值位参与比较
	// - writeMask 模板写入时的掩码，可以使用掩码来控制哪些位可以被写入模板缓冲区，掩码的每个1位表示对应的模板值位可以被更新
	VkPipelineDepthStencilStateCreateInfo depthStencilInfo{};
	// 6、颜色混合（Color Blending）；像素颜色的“混合器”
	// Attachment的本质就是给GPU准备的“专用数据容器”，用于存储GPU渲染时需要读取和写入的图像数据
	// VkPipelineColorBlendAttachmentState用于渲染管线中控制颜色混合行为的结构体，用于描述在渲染管线中如何将片元着色器输出的颜色与当前颜色附件进行合并
	// colorWriteMask 控制哪些颜色分量被写入到该Attachment的帧缓冲
	// VK_COLOR_COMPONENT_R_BIT（写红通道）、VK_COLOR_COMPONENT_G_BIT（写绿通道）、
	// VK_COLOR_COMPONENT_B_BIT（写蓝通道）、VK_COLOR_COMPONENT_A_BIT（写alpha通道）
	// blendEnable 是否启用该颜色的混合
	// colorBlendOp、alphaBlendOp 用于颜色通道混合运算符、用于alpha通道混合运算符
	// srcColorBlendFactor、dstColorBlendFactor 用于颜色混合的源因子与目标因子，决定在混合公式中对C_src和C_dst的乘权
	// VK_BLEND_FACTOR_ZERO（0）、VK_BLEND_FACTOR_ONE（1）、VK_BLEND_FACTOR_SRC_COLOR（C_src）、
	// VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR（1 - C_src）、VK_BLEND_FACTOR_DST_COLOR（C_dst）、
	// VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR（1 - C_dst）、VK_BLEND_FACTOR_SRC_ALPHA（A_src）、
	// VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA（1 - A_src）、VK_BLEND_FACTOR_DST_ALPHA（A_dst）、
	// VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA（1 - A_dst）、VK_BLEND_FACTOR_SRC_ALPHA_SATURATE（min(A_src, 1 - A_dst)）
	// 最终RGB颜色 = (srcColorBlendFactor * 源RGB) colorBlendOp (dstColorBlendFactor * 目标RGB)
	// srcAlphaBlendFactor、dstAlphaBlendFactor 用于控制源像素和目标像素在渲染合成时的透明度混合方式
	// VK_BLEND_FACTOR_ZERO（0）、VK_BLEND_FACTOR_ONE（1）、VK_BLEND_FACTOR_SRC_COLOR（C_src）、
	// VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR（1 - C_src）、VK_BLEND_FACTOR_DST_COLOR（C_dst）、
	// VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR（1 - C_dst）、VK_BLEND_FACTOR_SRC_ALPHA（A_src）、
	// VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA（1 - A_src）、VK_BLEND_FACTOR_DST_ALPHA（A_dst）、
	// VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA（1 - A_dst）、VK_BLEND_FACTOR_SRC_ALPHA_SATURATE（min(A_src, 1 - A_dst)）
	// 最终Alpha值 = (srcAlphaBlendFactor * 源Alpha) alphaBlendOp (dstAlphaBlendFactor * 目标Alpha)
	VkPipelineColorBlendAttachmentState colorBlendAttachmentInfo{};
	colorBlendAttachmentInfo.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
		VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
	colorBlendAttachmentInfo.blendEnable = VK_TRUE;
	colorBlendAttachmentInfo.colorBlendOp = VK_BLEND_OP_ADD;
	colorBlendAttachmentInfo.alphaBlendOp = VK_BLEND_OP_ADD;
	colorBlendAttachmentInfo.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
	colorBlendAttachmentInfo.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
	colorBlendAttachmentInfo.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
	colorBlendAttachmentInfo.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
	// VkPipelineColorBlendStateCreateInfo用于描述颜色混合状态的结构体，定义了如何将渲染管线中的颜色输出合成到帧缓冲区的目标图像中
	// sType 结构体标识
	// logicOpEnable 指定是否启用逻辑操作进行颜色混合
	// logicOp 设置逻辑操作的类型
	// VK_LOGIC_OP_CLEAR 结果全为0
	// VK_LOGIC_OP_AND 与操作
	// VK_LOGIC_OP_AND_REVERSE 源与反转目标
	// VK_LOGIC_OP_COPY 复制源
	// VK_LOGIC_OP_AND_INVERTED 源反转与目标
	// VK_LOGIC_OP_NO_OP 无操作
	// VK_LOGIC_OP_XOR 异或操作
	// VK_LOGIC_OP_OR 或操作
	// VK_LOGIC_OP_NOR 与非操作
	// VK_LOGIC_OP_EQUIV 等价操作
	// VK_LOGIC_OP_INVERT 取反操作
	// VK_LOGIC_OP_OR_REVERSE 反转源与目标或操作
	// VK_LOGIC_OP_COPY_INVERTED 复制反转的源
	// VK_LOGIC_OP_OR_INVERTED 反转源与目标或操作
	// VK_LOGIC_OP_NAND 与非操作
	// VK_LOGIC_OP_SET 结果全为1
	// attachmentCount 目标附件的数量，通常是帧缓冲的附件数量
	// pAttachments 指向VkPipelineColorBlendAttachmentState数组的指针，该数组指定了每个颜色附件的混合状态
	// blendConstants 四元组数组，指定了常数颜色混合因子（常用作混合公式中的固定值），用于logicOp中的某值
	// 只要开启logicOp（设logicOpEnable=VK_TRUE），颜色混合就会被强制按logicOp指定的固定逻辑执行，其他所有混合规则全作废
	VkPipelineColorBlendStateCreateInfo colorBlendInfo{};
	colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
	colorBlendInfo.logicOpEnable = VK_FALSE;
	colorBlendInfo.logicOp = VK_LOGIC_OP_COPY;
	colorBlendInfo.attachmentCount = 1;
	colorBlendInfo.pAttachments = &colorBlendAttachmentInfo;
	colorBlendInfo.blendConstants[0] = 0.f;
	colorBlendInfo.blendConstants[1] = 0.f;
	colorBlendInfo.blendConstants[2] = 0.f;
	colorBlendInfo.blendConstants[3] = 0.f;
	// 7、管线布局（VkPipelineLayout）：资源与管线的“接口契约”
	// VkPipelineLayoutCreateInfo用于创建管线布局的结构体 
	// sType 结构体标识
	// setLayoutCount 描述符集布局的数量
	// pSetLayouts 指向一个VkDescriptorSetLayout数组的指针，描述了每个描述符集的布局
	// - VkDescriptorSetLayout用于描述一个描述符集布局的结构体，是用来告诉GPU装了那些数据、数据怎么用、能从哪访问数据
	// - binding 描述符的绑定点，着色器使用这个绑定点来访问资源
	// - descriptorType 描述符的类型，表示资源的类型
	// - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER（Uniform缓冲区）、VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE（采样过的图像（纹理））、
	// - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER（存储缓冲区）、VK_DESCRIPTOR_TYPE_SAMPLER（采样器）、VK_DESCRIPTOR_TYPE_STORAGE_IMAGE（存储图像）、
	// - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER（结合了图像和采样器的描述符）
	// - descriptorCount 描述符的数量，一个绑定点可以使用多个描述符
	// - stageFlags 指定哪些着色器阶段可以访问这个描述符
	// - pImmutableSamplers 如果描述符是图像或采样器类型，可以提供一个不可变的采样器数组
	// pushConstantRangeCount 推送常量范围的数量，推送常量是一个小范围的、常用于传递小量数据的优化方式，通常是用来给着色器传递一些动态数据
	// pPushConstantRanges 指向一个VkPushConstantRange数组的指针，每个VkPushConstantRange结构体描述了一个推送常量的范围，定义了推送常量的大小和在着色器中的使用位置
	// - VkPushConstantRange用于描述推送常量范围的结构体
	// - stageFlags 指定了哪些着色器阶段会使用该推送常量
	// - VK_SHADER_STAGE_VERTEX_BIT 顶点着色器
	// - VK_SHADER_STAGE_FRAGMENT_BIT 片段着色器
	// - VK_SHADER_STAGE_COMPUTE_BIT 计算着色器
	// - VK_SHADER_STAGE_GEOMETRY_BIT 几何着色器
	// - VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT 细分控制着色器
	// - VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT 细分评估着色器
	// - VK_SHADER_STAGE_ALL_GRAPHICS：所有图形阶段
	// - VK_SHADER_STAGE_ALL 所有着色器阶段
	// - offset 推送常量的偏移位置（以字节为单位）,在管线布局中，每个推送常量范围都有一个偏移量，它用于指定数据在推送常量区域内的起始位置
	// - size 推送常量的大小，单位为字节，指定了该范围内的推送常量的大小，通常是与某种结构或数据类型的大小相匹配
	// 推送常量（Push Constants）是一种高效的方式来将小块数据从CPU传递到GPU，尤其是在不需要通过缓冲区更新的情况下，推送常量数据直接传递给GPU，并通过管线的状态寄存器（而不是缓冲区）进行访问，通常非常快速
	// 物理设备（GPU）渲染时需要很多外部数据，物理设备（GPU）不能直接访问这些数据，描述符集是专门用来给物理设备（GPU）输送渲染需要的外部数据（比如纹理、模型位置、灯光参数），还能规范数据的取用规则
	VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
	pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
	pipelineLayoutInfo.setLayoutCount = 0;
	pipelineLayoutInfo.pSetLayouts = nullptr;
	pipelineLayoutInfo.pushConstantRangeCount = 0;
	pipelineLayoutInfo.pPushConstantRanges = nullptr;
	// vkCreatePipelineLayout用于创建渲染管线布局对象的函数
	if (vkCreatePipelineLayout(this->logicDevice, &pipelineLayoutInfo, nullptr, &this->pipelineLayout) != VK_SUCCESS) {
		throw std::runtime_error("Failed to create pipeline layout!");
	}
	// VkDynamicState用来定义那些渲染管线状态可以在绘制过程中动态修改，而不需要重新创建整个管线
	// VK_DYNAMIC_STATE_VIEWPORT 视口可以通过vkCmdSetViewport()动态设置
	// VK_DYNAMIC_STATE_SCISSOR	裁剪矩形可通过vkCmdSetScissor()动态设置
	// VK_DYNAMIC_STATE_LINE_WIDTH 线宽可动态调整vkCmdSetLineWidth()
	// VK_DYNAMIC_STATE_DEPTH_BIAS 动态设置深度偏移vkCmdSetDepthBias()，常用于阴影消除
	// VK_DYNAMIC_STATE_BLEND_CONSTANTS	动态修改混合常量颜色vkCmdSetBlendConstants()
	// VK_DYNAMIC_STATE_DEPTH_BOUNDS 动态修改深度范围vkCmdSetDepthBounds()
	// VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK 动态修改模板测试比较掩码
	// VK_DYNAMIC_STATE_STENCIL_WRITE_MASK 动态修改模板写掩码
	// VK_DYNAMIC_STATE_STENCIL_REFERENCE	动态修改模板参考值
	std::vector<VkDynamicState> dynamicStates = {
		VK_DYNAMIC_STATE_VIEWPORT, 
		VK_DYNAMIC_STATE_SCISSOR
	};
	// VkPipelineDynamicStateCreateInfo描述图形管线创建时用来指定那些状态可以动态修改的结构体
	// sType 结构体标识
	// dynamicStateCount 指定动态状态数组的数量
	// pDynamicStates 指向VkDynamicState枚举数组，指定那些状态可修改
	VkPipelineDynamicStateCreateInfo dynamicInfo{};
	dynamicInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
	dynamicInfo.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
	dynamicInfo.pDynamicStates = dynamicStates.data();
	// VkGraphicsPipelineCreateInfo用于创建图形管线的结构体，图形管线定义了从顶点输入到最终图像输出的整个渲染过程，并涉及多个阶段的配置
	// sType 结构体标识
	// stageCount	图形管线中着色器阶段的数量
	// pStages 指向包含图形管线中可编程阶段的着色器阶段的描述信息数组的指针
	// pVertexInputState 指向VkPipelineVertexInputStateCreateInfo的指针，用于描述输入顶点数据的格式
	// pInputAssemblyState 指向VkPipelineInputAssemblyStateCreateInfo的指针，描述顶点输入汇编阶段的设置
	// pViewportState 指向VkPipelineViewportStateCreateInfo的指针，用于配置视口和剪裁矩形
	// pRasterizationState 指向VkPipelineRasterizationStateCreateInfo的指针，用于设置光栅化过程的相关选项（如线条宽度、填充模式等）
	// pMultisampleState 指向VkPipelineMultisampleStateCreateInfo的指针，用于多重采样的配置
	// pDepthStencilState 指向VkPipelineDepthStencilStateCreateInfo的指针，设置深度和模板测试的配置
	// pColorBlendState 指向VkPipelineColorBlendStateCreateInfo的指针，设置颜色混合相关的配置
	// pDynamicState 指向VkPipelineDynamicStateCreateInfo的指针，用于设置动态状态（如视口、剪裁矩形等），这些状态可以在渲染过程中动态改变
	// layout 图形管线使用的管线布局，通常由VkPipelineLayout创建，用于描述着色器如何访问资源（如常量缓冲区、纹理等）
	// renderPass 渲染通道（VkRenderPass），描述管线在渲染过程中的使用方式和目标
	// subpass 渲染通道的子通道索引，定义图形管线所属的子通道
	// basePipelineHandle 基本管线的句柄，如果是从另一个管线派生出来的，则指向该管线
	// basePipelineIndex 基本管线的索引，与basePipelineHandle配合使用，用于指定管线派生的方式
	VkGraphicsPipelineCreateInfo createInfo{};
	createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
	createInfo.stageCount = 2;
	createInfo.pStages = ShaderStageInfos;
	createInfo.pVertexInputState = &vertexInputInfo;
	createInfo.pInputAssemblyState = &assemblyInfo;
	createInfo.pViewportState = &viewportInfo;
	createInfo.pRasterizationState = &rasterizationInfo;
	createInfo.pMultisampleState = &multisampleInfo;
	createInfo.pDepthStencilState = &depthStencilInfo;
	createInfo.pColorBlendState = &colorBlendInfo;
	createInfo.pDynamicState = &dynamicInfo;
	createInfo.layout = this->pipelineLayout;
	createInfo.renderPass = this->renderPass;
	createInfo.subpass = 0;
	createInfo.basePipelineHandle = VK_NULL_HANDLE;
	std::vector<char> cacheData = readFile(pipelineCachePath);
	// VkPipelineCacheCreateInfo用于创建管线缓存的结构体，管线缓存可以加速图形管线的创建过程，通过存储先前创建的管线配置数据，避免重复创建相同的管线，从而提高性能
	// sType 结构体标识
	// initialDataSize 初始数据的大小，单位为字节，若有现成的管线缓存数据（如从文件加载的缓存），可以在这里提供数据大小
	// pInitialData指向初始数据的指针，若有管线缓存数据，可以通过这个字段提供
	VkPipelineCacheCreateInfo cacheInfo{};
	cacheInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
	cacheInfo.initialDataSize = cacheData.size();
	cacheInfo.pInitialData = cacheData.data();
	// VkPipelineCache用于缓存图形管线对象的句柄，管线缓存对象允许你缓存已经创建的管线配置，
	// 以便在后续的图形管线创建过程中复用这些管线，避免重复的计算和配置，从而提高应用程序的性能
	VkPipelineCache cache;
	// vkCreatePipelineCache用于创建管线缓存的函数，管线缓存用于存储已经创建的图形管线对象（VkPipeline）的配置数据，以便在后续的管线创建过程中复用这些数据，
	// 从而提高性能，特别是在程序启动时或需要多次创建相似管线时
	if (vkCreatePipelineCache(this->logicDevice, &cacheInfo, nullptr, &cache) == VK_SUCCESS) {
		// vkCreateGraphicsPipeline创建图形管线的函数，把定义的着色器、固定函数状态、管线布局、渲染通道等信息组合成一个GPU可用的管线对象
		if (vkCreateGraphicsPipelines(this->logicDevice, cache, 1, &createInfo, nullptr, &this->graphicsPipeline) != VK_SUCCESS) {
			throw std::runtime_error("Failed to create graphics pipeline!");
		}
		size_t cacheSize_;
		std::vector<char>	cacheData_;
		vkGetPipelineCacheData(this->logicDevice, cache, &cacheSize_, nullptr);
		cacheData_.resize(cacheSize_);
		// vkGetPipelineCacheData用于获取管线缓存数据的函数，主要用途是将已经创建并存储在管线缓存中的数据提取出来
		vkGetPipelineCacheData(this->logicDevice, cache, &cacheSize_, cacheData_.data());
		writeFile(pipelineCachePath, cacheData_, cacheSize_);
		// vkDestroyPipelineCache用于销毁管线缓存对象的函数
		vkDestroyPipelineCache(this->logicDevice, cache, nullptr);
	}
	else {
		// vkCreateGraphicsPipeline创建图形管线的函数，把定义的着色器、固定函数状态、管线布局、渲染通道等信息组合成一个GPU可用的管线对象
		if (vkCreateGraphicsPipelines(this->logicDevice, VK_NULL_HANDLE, 1, &createInfo, nullptr, &this->graphicsPipeline) != VK_SUCCESS) {
			throw std::runtime_error("Failed to create graphics pipeline!");
		}
	}
	// vkDestroyShaderModule用于销毁着色器模块的函数
	vkDestroyShaderModule(this->logicDevice, vertexShaderModule, nullptr);
	vkDestroyShaderModule(this->logicDevice, fragmentShaderModule, nullptr);
}

void test::createCommandPool()
{
	// VkCommandPoolCreateInfo用于创建关于命令池的配置信息的结构体
	// sType 结构体标识
	// flags 命令池的创建标志，用于控制池的行为，允许通过标志配置池的特性
	// VK_COMMAND_POOL_CREATE_TRANSIENT_BIT（表示命令缓冲区将短期内被使用，通常用于临时命令缓冲区。这些缓冲区创建后会很快被销毁）、
	// VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT（表示命令缓冲区可以被重置，这使得命令缓冲区可以多次重用，适用于重复记录命令的场景）
	// queueFamilyIndex 指定命令池所属的队列族的索引
	VkCommandPoolCreateInfo poolInfo{};
	poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
	poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
	poolInfo.queueFamilyIndex = q_Family.graphicsQueueFamily.value();
	// vkCreateCommandPool用于创建命令池的函数
	if (vkCreateCommandPool(this->logicDevice, &poolInfo, nullptr, &this->commandPool) != VK_SUCCESS) {
		throw std::runtime_error("Failed to create command pool!");
	}
}

void test::createCommandBuffers()
{
	// VkCommandBufferAllocateInfo用于分配命令缓冲区的结构体
	// sType 结构体标识
	// level 指定要分配的命令缓冲区的级别
	// VK_COMMAND_BUFFER_LEVEL_PRIMARY（主命令缓冲区，通常可以直接提交到队列执行）、
	// VK_COMMAND_BUFFER_LEVEL_SECONDARY（次命令缓冲区，不能直接提交，必须由主命令缓冲区调用）
	// commandBufferCount 指定要分配的命令缓冲区的数量
	// commandPool 指定命令缓冲区将从哪个命令池中分配
	VkCommandBufferAllocateInfo allocInfo{};
	allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
	allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
	allocInfo.commandBufferCount = 1;
	allocInfo.commandPool = commandPool;
	// vkAllocateCommandBuffers用于从命令池中分配命令缓冲区的函数
	if (vkAllocateCommandBuffers(this->logicDevice, &allocInfo, &this->commandBuffer) != VK_SUCCESS) {
		throw std::runtime_error("Failed to allocate command buffers!");
	}
}

void test::beginCommandBuffer(VkCommandBuffer& readyCommandBuffer, VkCommandBufferUsageFlags flags)
{
	// VkCommandBufferBeginInfo开始记录命令缓冲区时使用的结构体，和vkBeginCommandBuffer配合，告诉驱动命令缓冲区的使用方式和一些继承信息
	// sType 结构体标识
	// flags 指定命令缓冲区的使用行为
	// pInheritanceInfo 二级命令缓冲区专用，用于指定继承信息
	VkCommandBufferBeginInfo beginInfo{};
	beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
	beginInfo.flags = flags;
	beginInfo.pInheritanceInfo = nullptr;
	// vkBeginCommandBuffer用于开始记录命令缓冲区的函数，是每次向GPU提交绘制或计算命令前必须调用的接口
	if (vkBeginCommandBuffer(readyCommandBuffer, &beginInfo) != VK_SUCCESS) {
		throw std::runtime_error("Counldn`t begin command buffer!");
	}
}

void test::endCommandBuffer(VkCommandBuffer& readyCommandBuffer)
{
	// vkEndCommandBuffer用来结束命令缓冲区的录制，用于告诉GPU命令缓冲区的录制完成，可以提交执行
	if (vkEndCommandBuffer(readyCommandBuffer) != VK_SUCCESS) {
		throw std::runtime_error("Counldn`t end command buffer!");
	}
}

void test::recordCommandBuffer(VkCommandBuffer& recordCommandBuffer, uint32_t imageIndex)
{
	beginCommandBuffer(recordCommandBuffer, 0);
	// VkClearValue用来指定清除操作的颜色或深度/模板值的结构体，本质在RenderPass开始时，整个附件会被填充为指定的初始化值
	VkClearValue clearValue = { {{0.f, 0.f, 0.f, 1.f}} };
	// VkRenderPassBeginInfo用于启动RenderPass，指定使用的RenderPass、Framebuffer、渲染区域以及清屏值的结构体
	// sType 结构体标识
	// framebuffer 指定渲染的具体目标（实际的图像集合）
	// clearValueCount 表示清屏值的数量
	// pClearValues 用于指定每一个附件的初始清除值
	// renderArea 指定渲染操作实际作用的矩形区域
	VkRenderPassBeginInfo passBeginInfo{};
	passBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
	passBeginInfo.framebuffer = swapChainFrameBuffers[imageIndex];
	passBeginInfo.clearValueCount = 1;
	passBeginInfo.pClearValues = &clearValue;
	passBeginInfo.renderArea.offset = {0, 0};
	passBeginInfo.renderArea.extent = swapChainImageExtent;
	// vkCmdBeginRenderPass用于启动一个RenderPass的命令，必须在命令缓冲区中调用，告诉GPU从哪里开始渲染、渲染目标是哪块framebuffer、渲染区域是多大，以及如何清屏附件
	vkCmdBeginRenderPass(recordCommandBuffer, &passBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
	// vkCmdBindPipeline用于绑定管线操作，必须在命令缓冲区中调用，用于告诉GPU接下来的绘制命令使用这个管线对象
	vkCmdBindPipeline(recordCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, this->graphicsPipeline);
	// VkViewport用来定义视口参数的结构体，用来描述裁剪空间如何映射到帧缓冲区的矩形区域
	VkViewport viewport{};
	viewport.x = 0.f;
	viewport.y = 0.f;
	viewport.width = (float)swapChainImageExtent.width;
	viewport.height = (float)swapChainImageExtent.height;
	viewport.minDepth = 0.f;
	viewport.maxDepth = 1.f;
	// vkCmdSetViewport用于设置视口的命令，定义了从裁剪空间到帧缓冲的映射区域
	vkCmdSetViewport(recordCommandBuffer, 0, 1, &viewport);
	// VkRect2D定义二维矩形区域的结构体，经常用于renderArea、scissor等，用来指定渲染操作或像素裁剪的范围
	VkRect2D scissor{};
	scissor.offset = {0, 0};
	scissor.extent = swapChainImageExtent;
	// vkCmdSetScissor设置裁剪矩形的命令，用于限制像素写入framebuffer的区域
	vkCmdSetScissor(recordCommandBuffer, 0, 1, &scissor);
	// vkCmdDraw在命令缓冲区中发起非索引绘制的命令，用于告诉GPU使用当前绑定的管线、顶点缓冲和描述符集绘制顶点
	vkCmdDraw(recordCommandBuffer, 3, 1, 0, 0);
	// vkCmdEndRenderPass结束一个RenderPass的命令，必须在命令缓冲区中调用，用于告诉GPU当前RenderPass的渲染操作完成
	vkCmdEndRenderPass(recordCommandBuffer);
	endCommandBuffer(recordCommandBuffer);
}

void test::drawFrame()
{

}

VkShaderModule test::createShaderModule(const std::vector<char>& code)
{
	// VkShaderModuleCreateInfo用于描述如何创建一个着色器模块对象的结构体
	// sType 结构体标识
	// codeSize 指定着色器二进制的代码的大小，单位为字节
	// pCode 指向着色器二进制代码（SPIR-V）的指针
	VkShaderModuleCreateInfo createInfo{};
	createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
	createInfo.codeSize = code.size();
	createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
	VkShaderModule shaderModule;
	// VkResult用于表示Vulkan函数的执行结果
  // VK_SUCCESS 操作成功完成，通常是期望的结果
  // VK_NOT_READY 操作没有完成，但可以继续等待
  // VK_TIMEOUT 操作超时，通常用于等待某个操作完成时超时
  // VK_EVENT_SET 事件已设置，通常用于同步操作
  // VK_EVENT_RESET 事件已重置，表示事件状态为未触发
  // VK_INCOMPLETE 结果不完整，通常用于查询操作，表示未能返回所有需要的信息
  // VK_ERROR_OUT_OF_HOST_MEMORY 主机内存不足，无法为操作分配所需的内存
  // VK_ERROR_OUT_OF_DEVICE_MEMORY 设备内存不足，无法为操作分配所需的内存
  // VK_ERROR_INITIALIZATION_FAILED 初始化失败，通常是Vulkan实例或设备初始化时的错误
  // VK_ERROR_DEVICE_LOST 设备丢失，通常表示GPU设备在执行过程中发生了严重错误或崩溃
  // VK_ERROR_MEMORY_MAP_FAILED 内存映射失败，通常表示无法将内存对象映射到主机内存
  // VK_ERROR_LAYER_NOT_PRESENT 请求的Vulkan层未加载
  // VK_ERROR_EXTENSION_NOT_PRESENT 请求的Vulkan扩展未加载
  // VK_ERROR_FEATURE_NOT_PRESENT 请求的Vulkan特性不可用
  // VK_ERROR_INCOMPATIBLE_DRIVER 驱动程序与Vulkan版本不兼容
  // VK_ERROR_TOO_MANY_OBJECTS 创建的Vulkan对象数量过多，超出了设备的限制
  // VK_ERROR_FORMAT_NOT_SUPPORTED 请求的图像格式不被支持
  // VK_WARNING 操作执行时的警告，可能会导致性能问题，但不会影响操作的成功与否
  // VK_ERROR_UNKNOWN 未知错误，通常表示无法确定具体的错误原因
	VkResult results;
	// vkCreateShaderModule用于创建着色器模块的函数
	if ((results = vkCreateShaderModule(this->logicDevice, &createInfo, nullptr, &shaderModule)) != VK_SUCCESS) {
		switch (results) {
		case VK_ERROR_OUT_OF_HOST_MEMORY:
			std::cout << "The host is running low on memory!" << std::endl;
			break;
		case VK_ERROR_OUT_OF_DEVICE_MEMORY:
			std::cout << "The device is running low on memory!" << std::endl;
			break;
		default:
			std::cout << "Unknown Error!" << std::endl;
			break;
		}
		throw std::runtime_error("Failed to create shader module!");
	}
	return shaderModule;
}

void test::createFrameBuffers()
{
	this->swapChainFrameBuffers.resize(this->imageViews.size());
	for (int index = 0; index < this->imageViews.size(); index++) {
		VkImageView attachments[] = {
			this->imageViews[index]
		};
		// VkFramebufferCreateInfo用于创建VkFramebuffer对象的结构体
		// sType 结构体标识
		// attachmentCount 附件的数量，表示该帧缓冲有多少个附件图像
		// pAttachments 指向VkImageView数组的指针，每个VkImageView对象表示一个帧缓冲附件
		// width、height 定义了帧缓冲的宽度和高度，通常与交换链图像的大小一致，确保帧缓冲的尺寸适合渲染目标
		// layers 帧缓冲的层数，常规情况下为1，如果进行立体渲染或多目标渲染，可能会大于1
		// renderPass 指定与帧缓冲关联的VkRenderPass对象
		VkFramebufferCreateInfo createInfo{};
		createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
		createInfo.attachmentCount = 1;
		createInfo.pAttachments = attachments;
		createInfo.width = this->swapChainImageExtent.width;
		createInfo.height = this->swapChainImageExtent.height;
		createInfo.layers = 1;
		createInfo.renderPass = this->renderPass;
		// vkCreateFramebuffer用于创建帧缓冲的函数
		if (vkCreateFramebuffer(this->logicDevice, &createInfo, nullptr, &this->swapChainFrameBuffers[index]) != VK_SUCCESS) {
			throw std::runtime_error("Failed to create frame buffers!");
		}
	}
}

std::vector<char> test::readFile(const std::string& filePath)
{
	std::ifstream file(filePath, std::ios::ate | std::ios::binary);
	if (!file.is_open()) {
		throw std::runtime_error("Failed to open file!");
	}
	// tellg用来返回输入流指针的位置
	size_t fileSize = (size_t)file.tellg();
	// seekg用来设置输入流指针的位置
	file.seekg(0);
	std::vector<char> fileData(fileSize);
	file.read(fileData.data(), fileSize);
	return fileData;
}

void test::writeFile(const std::string& filePath, std::vector<char> data, size_t dataSize)
{
	std::ofstream file(filePath, std::ios::out | std::ios::binary);
	if (!file.is_open()) {
		throw std::runtime_error("Failed to open file!");
	}
	file.write(data.data(), dataSize);
}

VKAPI_ATTR VkBool32 VKAPI_CALL test::debugCallback(
	VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, 
	VkDebugUtilsMessageTypeFlagsEXT messageType, 
	const VkDebugUtilsMessengerCallbackDataEXT* messengerData, 
	void* pUserData)
{
	std::cerr << "Validation Layer: " << messengerData->pMessage << std::endl;
	if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
		return VK_TRUE;
	}
	return VK_FALSE;
}

void test::run() {
	// glfwWindowShouldClose是GLFW库的函数，用于检查窗口是否应该关闭
	while (!glfwWindowShouldClose(this->window)) {
		// glfwPollEvents是GLFW库的函数，用于处理所有挂起的事件，并更新窗口的状态
		glfwPollEvents();
	}
}

test::~test() {
	cleanupAll();
}

void test::cleanupAll() {
	cleanupVulkan();
	cleanupWindow();
}

void test::cleanupWindow() {
	// glfwDestroyWindow是GLFW库的函数，用于销毁一个已创建的窗口并释放与该窗口相关的所有资源
	glfwDestroyWindow(this->window);
	// glfwTerminate是GLFW库的函数，用于终止GLFW库的使用并释放所有与GLFW相关的资源
	glfwTerminate();
}

void test::cleanupVulkan()
{
	for (int index = 0; index < swapChainFrameBuffers.size(); index++) {
		// vkDestroyFramebuffer用于销毁帧缓冲对象的函数
		vkDestroyFramebuffer(this->logicDevice, this->swapChainFrameBuffers[index], nullptr);
	}
	// vkDestroyPipeline用于销毁管线对象的函数
	vkDestroyPipeline(this->logicDevice, this->graphicsPipeline, nullptr);
	// vkDestroyRenderPass用于销毁渲染通道对象的函数
	vkDestroyRenderPass(this->logicDevice, this->renderPass, nullptr);
	// vkDestoryPipelineLayout用于销毁管线布局对象的函数
	vkDestroyPipelineLayout(this->logicDevice, this->pipelineLayout, nullptr);
	for (const auto& imageview : imageViews) {
		// vkDestroyImageView用于销毁图像视图对象的函数
		vkDestroyImageView(this->logicDevice, imageview, nullptr);
	}
	// vkDestroySwapchainKHR用于销毁交换链的函数
	vkDestroySwapchainKHR(this->logicDevice, this->swapChain, nullptr);
	// vkDestroySurfaceKHR用于销毁与窗口系统相关联的Vulkan表面
	vkDestroySurfaceKHR(this->instance, this->surface, nullptr);
	// vlDestroyDevice用于销毁逻辑设备对象的函数
	vkDestroyDevice(this->logicDevice, nullptr);
	if (enabledValidationLayer) {
		destroyDebugUtilsMessenger(this->instance, this->debugMessenger, nullptr);
	}
	// vkDestroyInstance用于销毁Vulkan实例的函数
	vkDestroyInstance(this->instance, nullptr);
}
